From b7c498208cf4d26f4c34962035873cbe0dac525a Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk[cl349]" Date: Wed, 11 May 2005 13:04:09 +0000 Subject: [PATCH] bitkeeper revision 1.1389.15.10 (428202c9Vz9xfNsG-q-WtZpPrER7xQ) [PATCH] xen,tools: pincpu use vcpu and cpumap_t The following patch updates the dom0 pincpu operation to read the VCPU value from the xend interface rather than hard-coding the exec_domain to 0. This prevented pinning VCPUS other than 0 to a particular cpu. The pincpu cpu argument is replaced with cpumap, a u64 bitmap representing which CPUs a VCPU can use. I added the number of VCPUS to the main xm list output and also included a new sub-option to xm list to display the VCPU to CPU mapping. While working on the pincpu code, I fixed an out-of-bounds indexing for the pincpu operation that wasn't previously exposed since the vcpu/exec_domain value was hard-coded to 0. Signed-off-by: Ryan Harper Signed-off-by: Christian Limpach --- tools/libxc/xc.h | 6 +- tools/libxc/xc_domain.c | 16 +++-- tools/python/xen/lowlevel/xc/xc.c | 71 ++++++++++++++--------- tools/python/xen/xend/XendClient.py | 5 +- tools/python/xen/xend/XendDomain.py | 11 ++-- tools/python/xen/xend/XendDomainInfo.py | 6 +- tools/python/xen/xend/server/SrvDomain.py | 3 +- tools/python/xen/xend/server/SrvUsbif.py | 1 + tools/python/xen/xm/main.py | 67 +++++++++++++++++---- xen/arch/x86/domain.c | 1 + xen/common/dom0_ops.c | 38 ++++++++++-- xen/common/domain.c | 1 + xen/include/public/dom0_ops.h | 7 ++- xen/include/public/xen.h | 2 + xen/include/xen/sched.h | 4 ++ 15 files changed, 179 insertions(+), 60 deletions(-) diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h index dd7a712ad6..861285bb94 100644 --- a/tools/libxc/xc.h +++ b/tools/libxc/xc.h @@ -111,6 +111,7 @@ int xc_waitdomain_core(int domain, typedef struct { u32 domid; unsigned int cpu; + unsigned int vcpus; unsigned int dying:1, crashed:1, shutdown:1, paused:1, blocked:1, running:1; unsigned int shutdown_reason; /* only meaningful if shutdown==1 */ @@ -118,6 +119,8 @@ typedef struct { unsigned long shared_info_frame; u64 cpu_time; unsigned long max_memkb; + u32 vcpu_to_cpu[MAX_VIRT_CPUS]; + cpumap_t cpumap[MAX_VIRT_CPUS]; } xc_dominfo_t; typedef dom0_getdomaininfo_t xc_domaininfo_t; @@ -167,7 +170,8 @@ int xc_domain_destroy(int xc_handle, u32 domid); int xc_domain_pincpu(int xc_handle, u32 domid, - int cpu); + int vcpu, + cpumap_t *cpumap); /** * This function will return information about one or more domains. * diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 488139cfd1..4cb65dbfbb 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -16,6 +16,8 @@ int xc_domain_create(int xc_handle, { int err, errno_saved; dom0_op_t op; + u32 vcpu = 0; /* FIXME, hard coded initial pin to vcpu 0 */ + cpumap_t cpumap = 1<max_memkb = op.u.getdomaininfo.max_pages<<(PAGE_SHIFT); info->shared_info_frame = op.u.getdomaininfo.shared_info_frame; info->cpu_time = op.u.getdomaininfo.cpu_time; + info->vcpus = op.u.getdomaininfo.n_vcpu; + memcpy(info->vcpu_to_cpu, &op.u.getdomaininfo.vcpu_to_cpu, + MAX_VIRT_CPUS*sizeof(u32)); + memcpy(info->cpumap, &op.u.getdomaininfo.cpumap, + MAX_VIRT_CPUS*sizeof(cpumap_t)); next_domid = (u16)op.u.getdomaininfo.domain + 1; info++; diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index faa6e06d62..1a0470aaae 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -155,15 +155,16 @@ static PyObject *pyxc_domain_pincpu(PyObject *self, XcObject *xc = (XcObject *)self; u32 dom; - int cpu = -1; + int vcpu = 0; + cpumap_t cpumap = 0xFFFFFFFF; - static char *kwd_list[] = { "dom", "cpu", NULL }; + static char *kwd_list[] = { "dom", "vcpu", "cpumap", NULL }; - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, - &dom, &cpu) ) + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|ii", kwd_list, + &dom, &vcpu, &cpumap) ) return NULL; - if ( xc_domain_pincpu(xc->xc_handle, dom, cpu) != 0 ) + if ( xc_domain_pincpu(xc->xc_handle, dom, vcpu, &cpumap) != 0 ) return PyErr_SetFromErrno(xc_error); Py_INCREF(zero); @@ -175,10 +176,10 @@ static PyObject *pyxc_domain_getinfo(PyObject *self, PyObject *kwds) { XcObject *xc = (XcObject *)self; - PyObject *list; + PyObject *list, *vcpu_list, *cpumap_list, *info_dict; u32 first_dom = 0; - int max_doms = 1024, nr_doms, i; + int max_doms = 1024, nr_doms, i, j; xc_dominfo_t *info; static char *kwd_list[] = { "first_dom", "max_doms", NULL }; @@ -195,23 +196,34 @@ static PyObject *pyxc_domain_getinfo(PyObject *self, list = PyList_New(nr_doms); for ( i = 0 ; i < nr_doms; i++ ) { - PyList_SetItem( - list, i, - Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" - ",s:l,s:L,s:l,s:i}", - "dom", info[i].domid, - "cpu", info[i].cpu, - "dying", info[i].dying, - "crashed", info[i].crashed, - "shutdown", info[i].shutdown, - "paused", info[i].paused, - "blocked", info[i].blocked, - "running", info[i].running, - "mem_kb", info[i].nr_pages*4, - "cpu_time", info[i].cpu_time, - "maxmem_kb", info[i].max_memkb, - "shutdown_reason", info[i].shutdown_reason - )); + vcpu_list = PyList_New(MAX_VIRT_CPUS); + cpumap_list = PyList_New(MAX_VIRT_CPUS); + for ( j = 0; j < MAX_VIRT_CPUS; j++ ) { + PyList_SetItem( vcpu_list, j, + Py_BuildValue("i", info[i].vcpu_to_cpu[j])); + PyList_SetItem( cpumap_list, j, + Py_BuildValue("i", info[i].cpumap[j])); + } + + info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" + ",s:l,s:L,s:l,s:i}", + "dom", info[i].domid, + "cpu", info[i].cpu, + "vcpus", info[i].vcpus, + "dying", info[i].dying, + "crashed", info[i].crashed, + "shutdown", info[i].shutdown, + "paused", info[i].paused, + "blocked", info[i].blocked, + "running", info[i].running, + "mem_kb", info[i].nr_pages*4, + "cpu_time", info[i].cpu_time, + "maxmem_kb", info[i].max_memkb, + "shutdown_reason", info[i].shutdown_reason); + PyDict_SetItemString( info_dict, "vcpu_to_cpu", vcpu_list ); + PyDict_SetItemString( info_dict, "cpumap", cpumap_list ); + PyList_SetItem( list, i, info_dict); + } free(info); @@ -959,9 +971,10 @@ static PyMethodDef pyxc_methods[] = { { "domain_pincpu", (PyCFunction)pyxc_domain_pincpu, METH_VARARGS | METH_KEYWORDS, "\n" - "Pin a domain to a specified CPU.\n" - " dom [int]: Identifier of domain to be pinned.\n" - " cpu [int, -1]: CPU to pin to, or -1 to unpin\n\n" + "Pin a VCPU to a specified set CPUs.\n" + " dom [int]: Identifier of domain to which VCPU belongs.\n" + " vcpu [int, 0]: VCPU being pinned.\n" + " cpumap [int, -1]: Bitmap of usable CPUs.\n\n" "Returns: [int] 0 on success; -1 on error.\n" }, { "domain_getinfo", @@ -976,6 +989,7 @@ static PyMethodDef pyxc_methods[] = { " domain-id space was reached.\n" " dom [int]: Identifier of domain to which this info pertains\n" " cpu [int]: CPU to which this domain is bound\n" + " vcpus [int]: Number of Virtual CPUS in this domain\n" " dying [int]: Bool - is the domain dying?\n" " crashed [int]: Bool - has the domain crashed?\n" " shutdown [int]: Bool - has the domain shut itself down?\n" @@ -986,7 +1000,8 @@ static PyMethodDef pyxc_methods[] = { " maxmem_kb [int]: Maximum memory limit, in kilobytes\n" " cpu_time [long]: CPU time consumed, in nanoseconds\n" " shutdown_reason [int]: Numeric code from guest OS, explaining " - "reason why it shut itself down.\n" }, + "reason why it shut itself down.\n" + " vcpu_to_cpu [[int]]: List that maps VCPUS to CPUS\n" }, { "linux_save", (PyCFunction)pyxc_linux_save, diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index c762cb64a9..39a72a43b7 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -246,10 +246,11 @@ class Xend: 'live' : live, 'resource' : resource }) - def xend_domain_pincpu(self, id, cpu): + def xend_domain_pincpu(self, id, vcpu, cpumap): return self.xendPost(self.domainurl(id), {'op' : 'pincpu', - 'cpu' : cpu }) + 'vcpu' : vcpu, + 'cpumap' : cpumap }) def xend_domain_cpu_bvt_set(self, id, mcuadv, warpback, warpvalue, warpl, warpu): return self.xendPost(self.domainurl(id), diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 2a4d472143..71f2cd8020 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -612,15 +612,16 @@ class XendDomain: xmigrate = XendMigrate.instance() return xmigrate.save_begin(dominfo, dst) - def domain_pincpu(self, id, cpu): - """Pin a domain to a cpu. + def domain_pincpu(self, id, vcpu, cpumap): + """Set which cpus vcpu can use - @param id: domain - @param cpu: cpu number + @param id: domain + @param vcpu: vcpu number + @param cpumap: bitmap of usbale cpus """ dominfo = self.domain_lookup(id) try: - return xc.domain_pincpu(int(dominfo.id), cpu) + return xc.domain_pincpu(int(dominfo.id), vcpu, cpumap) except Exception, ex: raise XendError(str(ex)) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index e97266b303..a040d31545 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -372,6 +372,10 @@ class XendDomainInfo: sxpr.append(['shutdown_reason', reason]) sxpr.append(['cpu', self.info['cpu']]) sxpr.append(['cpu_time', self.info['cpu_time']/1e9]) + sxpr.append(['vcpus', self.info['vcpus']]) + sxpr.append(['cpumap', self.info['cpumap']]) + sxpr.append(['vcpu_to_cpu', ''.join(map(lambda x: str(x), + self.info['vcpu_to_cpu'][0:self.info['vcpus']]))]) if self.start_time: up_time = time.time() - self.start_time @@ -449,7 +453,7 @@ class XendDomainInfo: raise VmError('missing memory size') cpu = sxp.child_value(config, 'cpu') if self.recreate and self.dom and cpu is not None: - xc.domain_pincpu(self.dom, int(cpu)) + xc.domain_pincpu(self.dom, 0, 1< 1: + (x,y) = c.split('-') + for i in range(int(x),int(y)+1): + cpus.append(int(i)) + else: + cpus.append(int(c)) + cpus.sort() + for c in cpus: + cpumap = cpumap | 1<shared_info = (void *)alloc_xenheap_page(); memset(d->shared_info, 0, PAGE_SIZE); ed->vcpu_info = &d->shared_info->vcpu_data[ed->id]; + ed->cpumap = CPUMAP_RUNANYWHERE; SHARE_PFN_WITH_DOMAIN(virt_to_page(d->shared_info), d); machine_to_phys_mapping[virt_to_phys(d->shared_info) >> PAGE_SHIFT] = INVALID_M2P_ENTRY; diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 23fc589d4d..8963d5dbda 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -221,7 +221,8 @@ long do_dom0_op(dom0_op_t *u_dom0_op) domid_t dom = op->u.pincpudomain.domain; struct domain *d = find_domain_by_id(dom); struct exec_domain *ed; - int cpu = op->u.pincpudomain.cpu; + cpumap_t curmap, *cpumap = &curmap; + if ( d == NULL ) { @@ -229,6 +230,14 @@ long do_dom0_op(dom0_op_t *u_dom0_op) break; } + if ( (op->u.pincpudomain.exec_domain >= MAX_VIRT_CPUS) || + !d->exec_domain[op->u.pincpudomain.exec_domain] ) + { + ret = -EINVAL; + put_domain(d); + break; + } + ed = d->exec_domain[op->u.pincpudomain.exec_domain]; if ( ed == NULL ) { @@ -244,17 +253,29 @@ long do_dom0_op(dom0_op_t *u_dom0_op) break; } - if ( cpu == -1 ) + if ( copy_from_user(cpumap, + op->u.pincpudomain.cpumap, sizeof(*cpumap)) ) { - clear_bit(EDF_CPUPINNED, &ed->flags); + ret = -EFAULT; + put_domain(d); + break; } + + /* update cpumap for this ed */ + ed->cpumap = *(cpumap); + + if ( *(cpumap) == CPUMAP_RUNANYWHERE ) + clear_bit(EDF_CPUPINNED, &ed->flags); else { + /* pick a new cpu from the usable map */ + int new_cpu = (int)find_first_set_bit(*(cpumap)) % smp_num_cpus; + exec_domain_pause(ed); - if ( ed->processor != (cpu % smp_num_cpus) ) + if ( ed->processor != new_cpu ) set_bit(EDF_MIGRATED, &ed->flags); set_bit(EDF_CPUPINNED, &ed->flags); - ed->processor = cpu % smp_num_cpus; + ed->processor = new_cpu; exec_domain_unpause(ed); } @@ -308,6 +329,12 @@ long do_dom0_op(dom0_op_t *u_dom0_op) break; } + memset(&op->u.getdomaininfo.vcpu_to_cpu,-1,MAX_VIRT_CPUS*sizeof(u8)); + for_each_exec_domain ( d, ed ) { + op->u.getdomaininfo.vcpu_to_cpu[ed->id] = ed->processor; + op->u.getdomaininfo.cpumap[ed->id] = ed->cpumap; + } + ed = d->exec_domain[op->u.getdomaininfo.exec_domain]; op->u.getdomaininfo.flags = @@ -325,6 +352,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op) op->u.getdomaininfo.tot_pages = d->tot_pages; op->u.getdomaininfo.max_pages = d->max_pages; op->u.getdomaininfo.cpu_time = ed->cpu_time; + op->u.getdomaininfo.n_vcpu = d->shared_info->n_vcpu; op->u.getdomaininfo.shared_info_frame = __pa(d->shared_info) >> PAGE_SHIFT; diff --git a/xen/common/domain.c b/xen/common/domain.c index 7ab17768c6..6f729eb2ec 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -283,6 +283,7 @@ long do_boot_vcpu(unsigned long vcpu, struct vcpu_guest_context *ctxt) ed = d->exec_domain[vcpu]; atomic_set(&ed->pausecnt, 0); + ed->cpumap = CPUMAP_RUNANYWHERE; memcpy(&ed->arch, &idle0_exec_domain.arch, sizeof(ed->arch)); diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h index 869a959f6c..d27a7f0ac1 100644 --- a/xen/include/public/dom0_ops.h +++ b/xen/include/public/dom0_ops.h @@ -88,6 +88,9 @@ typedef struct { memory_t max_pages; memory_t shared_info_frame; /* MFN of shared_info struct */ u64 cpu_time; + u32 n_vcpu; + u32 vcpu_to_cpu[MAX_VIRT_CPUS]; /* current mapping */ + cpumap_t cpumap[MAX_VIRT_CPUS]; /* allowable mapping */ } dom0_getdomaininfo_t; #define DOM0_SETDOMAININFO 13 @@ -170,14 +173,14 @@ typedef struct { } dom0_readconsole_t; /* - * Pin Domain to a particular CPU (use -1 to unpin) + * Set which cpus an exec_domain can use */ #define DOM0_PINCPUDOMAIN 20 typedef struct { /* IN variables. */ domid_t domain; u16 exec_domain; - s32 cpu; /* -1 implies unpin */ + cpumap_t *cpumap; } dom0_pincpudomain_t; /* Get trace buffers machine base address */ diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index 7dc30c9dc6..e3ba5e9b06 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -473,6 +473,8 @@ typedef struct { /* For use in guest OSes. */ extern shared_info_t *HYPERVISOR_shared_info; +typedef u64 cpumap_t; + #endif /* !__ASSEMBLY__ */ #endif /* __XEN_PUBLIC_XEN_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 6f64e0c057..7ab3e0fa93 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -58,6 +58,8 @@ int init_event_channels(struct domain *d); void destroy_event_channels(struct domain *d); int init_exec_domain_event_channels(struct exec_domain *ed); + +#define CPUMAP_RUNANYWHERE 0xFFFFFFFF struct exec_domain { int id; @@ -84,6 +86,8 @@ struct exec_domain atomic_t pausecnt; + cpumap_t cpumap; /* which cpus this domain can run on */ + struct arch_exec_domain arch; }; -- 2.30.2